#include "proxy/ipipnet/ipipnet_manager.h"
#include <fstream>

namespace proxy{

  IpipnetManager::IpipnetManager()
    :p_ip_index_(NULL), p_ip_data_(NULL),index_size_(0){

  }

  bool IpipnetManager::InitIpipnetManager(const std::string data_file){
    std::ifstream data_file_stream(data_file, std::ios::binary);
    if (!data_file_stream.is_open()){
      LOG(ERROR) << "Failure to open the ipipnet file : " << data_file;
      return false;
    }

    ip_data_.assign(std::istreambuf_iterator<char>(data_file_stream),
      std::istreambuf_iterator<char>());
    LOG(INFO) << "Load bytes " << ip_data_.size();

    unsigned int net_index_size = 0;
    memcpy(&net_index_size, &ip_data_[0], 4);
    index_size_ = ntohl(net_index_size);

    p_ip_index_ = &ip_data_[4];
    p_ip_data_ = &ip_data_[index_size_];
    return true;
  }

  std::string IpipnetManager::Search(const std::string ip_str){

    unsigned int network_ip = inet_addr(ip_str.c_str());
    unsigned int nip = ntohl(network_ip);

    // atoi The string can contain additional characters after those 
    // that form the integral number, which are ignored and have no 
    // effect on the behavior of this function.
    int first = atoi(ip_str.c_str());
    int start = 0;
    memcpy(&start, p_ip_index_ + (first * 4), 4);
    int iMaxComLen = p_ip_data_ - p_ip_index_ - 1024 - 4;

    int iIndexOffset = -1;
    unsigned char ucIndexLength = 0;
    for (start = start * 8 + 1024; start < iMaxComLen; start += 8) {
      unsigned int uiCurrIP = 0;
      memcpy(&uiCurrIP, p_ip_index_ + start, 4);
      uiCurrIP = ntohl(uiCurrIP);
      if (uiCurrIP >= nip) {
        iIndexOffset = 0;
        memcpy(&iIndexOffset, p_ip_index_ + start + 4, 3);
        memcpy(&ucIndexLength, p_ip_index_ + start + 7, 1);
        break;
      }
    }

    if (iIndexOffset == -1) {
      return "NOT FOUND";
    }

    std::string strRegion(p_ip_data_ + iIndexOffset - 1024, ucIndexLength);
    return strRegion;
  }
}